<template>
  <div class="page">
    <el-row class="panels" :gutter="20">
      <el-col :span="16">
        <div class="video-box border-1">
          <div class="watch-visitor">
            <div class="box">
              <whiteboard
                ref="whiteboardRef"
                @getMessage="getWhiteboardData"
                :whiteboard-data="whiteboardData"
                :is-show="whiteboardSwitch"
                v-show="
                  whiteboardSwitch &&
                  whiteboardData.username === userData.username
                "
              />
              <div v-if="whiteboardSwitch">
                <img
                  v-show="whiteboardData.username !== userData.username"
                  :src="whiteboardData.image"
                  alt=""
                />
              </div>
              <video
                v-else-if="videoSrc"
                :srcObject="videoSrc"
                autoplay
              ></video>
              <span v-else>欢迎使用视频会议</span>
            </div>
            <div class="other-visitor">
              <video
                v-if="remoteVideoSrc"
                :srcObject="remoteVideoSrc"
                controls
                autoplay
                height="160"
                width="160"
              ></video>
              <span v-else>欢迎使用视频会议</span>
            </div>
          </div>
          <div class="control-bar">
            <el-button type="primary" @click="whiteboardControl">
              {{ whiteboardSwitch ? "关闭" : "打开" }}画板
            </el-button>
            <el-button type="primary" @click="exit">退出房间</el-button>
            <el-button
              type="primary"
              @click="soundControl(!soundSwitch)"
              v-if="cameraSwitch"
            >
              {{ soundSwitch ? "关闭" : "打开" }}声音
            </el-button>
            <el-button type="primary" @click="closeCamera" v-if="cameraSwitch">
              关闭摄像头
            </el-button>
            <el-button type="primary" @click="openCamera" v-else>
              打开摄像头
            </el-button>
          </div>
        </div>
      </el-col>
      <el-col :span="8">
        <div class="chart-box">
          <div class="chart-box-info">
            <chart :message-list="messageList" :userData="userData" />
          </div>
          <div class="chart-box-input">
            <el-input
              v-model="putMessage"
              type="textarea"
              :rows="2"
              :autosize="false"
              resize="none"
              placeholder="请输入"
              maxlength="100"
            ></el-input>
            <div>
              <el-button @click="clearPerpareMessage">清空</el-button>
              <el-button type="primary" @click="putMessageSocket">
                发送
              </el-button>
            </div>
          </div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>

<script setup lang="ts">
import { nextTick, reactive, ref, watch } from "vue";
import Chart from "../components/Chart.vue";
import { useRouter } from "vue-router";
import { uuid } from "vue-uuid";
import Whiteboard from "../components/Whiteboard.vue";

const router = useRouter();

const videoSrc = ref();
const cameraStream = ref();
const media = ref();
const ws = ref();
const localUUID = uuid.v4();
const whiteboardRef = ref();
const whiteboardData = ref<IImage>({
  type: "guest",
  username: "",
  roomId: "",
  image: "",
});

const soundSwitch = ref(false);
const cameraSwitch = ref(false);
const whiteboardSwitch = ref(false);

const userData = ref<IUserData>({
  roomId: "",
  sex: "boy",
  username: "",
});

// 初始化摄像头
const initCamera = () => {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    alert("当前浏览器不支持视频录制");
    return;
  }
  media.value = navigator.mediaDevices.getUserMedia;
};

// 关闭摄像头
const closeCamera = () => {
  videoSrc.value = null;
  cameraStream.value.getTracks().forEach((item: any) => {
    item.stop();
  });
  const newMessage: IMessage = {
    type: "video_close",
    sex: userData.value.sex,
    username: userData.value.username,
    roomId: userData.value.roomId,
    message: "",
  };
  ws.value.send(JSON.stringify(newMessage));
  cameraStream.value = null;
  cameraSwitch.value = false;
  soundSwitch.value = false;
};

// 打开摄像头
let localRTCConnection: RTCPeerConnection;
const openCamera = async () => {
  if (!media.value || cameraStream.value) return;
  const stream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true,
  });
  videoSrc.value = stream;
  cameraStream.value = stream;
  let localSDP = "";
  localRTCConnection = new RTCPeerConnection();
  stream.getTracks().forEach((track: any) => {
    localRTCConnection.addTrack(track, stream);
  });
  const dc = localRTCConnection.createDataChannel("channel");
  dc.onmessage = (e) => console.log("Just got a message " + e.data);
  dc.onopen = (e) => console.log("Connection opened!");
  localRTCConnection.onicecandidate = (e) => {
    console.log("New Ice Candidate! reprinting SDP");
    localSDP = JSON.stringify(localRTCConnection.localDescription);
  };
  localRTCConnection
    .createOffer()
    .then((o) => localRTCConnection.setLocalDescription(o))
    .then((a) => {
      console.log("set Successlly");
    });

  setTimeout(() => {
    const newMessage: IMessage = {
      type: "video",
      message: localSDP,
      username: userData.value.username,
      roomId: userData.value.roomId,
      sex: userData.value.sex,
      uuid: localUUID,
    };
    ws.value.send(JSON.stringify(newMessage));
  }, 200);

  soundSwitch.value = true;
  cameraSwitch.value = true;
};

// 关闭声音
const soundControl = (val: boolean) => {
  if (!cameraStream.value) return;
  const sound = cameraStream.value
    .getTracks()
    .find((item: any) => item.kind === "audio");
  sound.enabled = val;
  soundSwitch.value = val;
};

// 待发送的消息
const putMessage = ref("");
const messageList = ref<IMessage[]>([]);

// 建立socket连接时
const openSocket = () => {
  const newMessage: IMessage = {
    type: "hint",
    username: userData.value.username,
    roomId: userData.value.roomId,
    sex: userData.value.sex,
    message: "连接成功",
  };
  ws.value.send(JSON.stringify(newMessage));
};

// 关闭socket连接时
const closeSocket = () => {
  console.log("连接关闭");
};

// 监听socket消息
const remoteVideoSrc = ref();
const getMessageSocket = (msg: any) => {
  const message: IMessage = JSON.parse(msg.data);
  if (message.type === "video_close") {
    if (message.username === userData.value.username) return;
    remoteVideoSrc.value = null;
    return;
  }
  if (message.type === "video") {
    if (message.uuid === localUUID) {
      const answer = JSON.parse(message.message);
      localRTCConnection.setRemoteDescription(answer);
    } else {
      const offer = JSON.parse(message.message);
      const rc = new RTCPeerConnection();
      let localSDP = "";
      rc.onicecandidate = (e) => {
        console.log("New Ice Candidate! reprinting SDP");
        localSDP = JSON.stringify(rc.localDescription);
      };
      let dc: RTCDataChannel;
      rc.ondatachannel = (e) => {
        dc = e.channel;
        dc.onmessage = (e) => console.log("new message from client! " + e.data);
        dc.onopen = (e) => console.log("Connection OPENED!!!!");
      };
      rc.setRemoteDescription(offer).then((a) => console.log("offer set!"));
      rc.createAnswer()
        .then((a) => rc.setLocalDescription(a))
        .then((a) => {
          console.log("answer created");
        });
      rc.ontrack = (e) => {
        remoteVideoSrc.value = e.streams[0];
      };
      setTimeout(() => {
        const newMessage: IMessage = {
          type: "video",
          username: userData.value.username,
          roomId: userData.value.roomId,
          sex: userData.value.sex,
          uuid: message.uuid,
          message: localSDP,
        };
        ws.value.send(JSON.stringify(newMessage));
      }, 200);
    }
    return;
  }
  messageList.value.push(message);
};

// 发送socket消息
const putMessageSocket = () => {
  const newMessage: IMessage = {
    type: "user",
    username: userData.value.username,
    roomId: userData.value.roomId,
    sex: userData.value.sex,
    message: putMessage.value,
  };
  ws.value.send(JSON.stringify(newMessage));
  putMessage.value = "";
};

// 清空输入框
const clearPerpareMessage = () => {
  putMessage.value = "";
};

// 监听socket错误
const errorSocket = (msg: any) => {
  alert("服务器连接失败");
};

const initWebSocket = () => {
  try {
    userData.value = JSON.parse(localStorage.getItem("userData") || "");
    ws.value = new WebSocket(
      `ws://127.0.0.1:8080/chart-room/${userData.value.roomId}`
    );
    ws.value.onopen = openSocket;
    ws.value.onclose = closeSocket;
    ws.value.onerror = errorSocket;
    ws.value.onmessage = getMessageSocket;
  } catch {
    router.push("/");
  }
};

const getWhiteboardData = (res: IImage) => {
  if (res.type === "close") {
    whiteboardSwitch.value = false;
    whiteboardData.value = {
      type: "guest",
      username: "",
      roomId: "",
      image: "",
    };
    return;
  }
  whiteboardSwitch.value = true;
  whiteboardData.value = res;
};

const whiteboardControl = () => {
  whiteboardSwitch.value = !whiteboardSwitch.value;
  if (!whiteboardSwitch.value) {
    whiteboardRef.value.closeWhiteboard();
  }
};

const exit = () => {
  localStorage.clear();
  router.push("/");
};

// 初始化
const onInit = () => {
  initWebSocket();
  initCamera();
};
onInit();
</script>

<style lang="scss" scoped>
.border-1 {
  border: 1px solid #dcdfe6;
}
.page {
  padding: 20px;
  min-width: 1300px;
}
.panels {
  height: 800px;
  .video-box {
    .watch-visitor {
      display: flex;
      .box {
        flex: 1;
        height: 750px;
        display: flex;
        justify-content: center;
        align-items: center;
        video {
          object-fit: contain;
          width: 80%;
          height: 750px;
        }
      }
    }
    .other-visitor {
      text-align: center;
      flex: 1;
      border-left: 1px solid #dcdfe6;
      display: flex;
      justify-content: center;
      align-items: center;
      video {
        object-fit: contain;
        width: 80%;
        height: 750px;
      }
    }
  }

  .control-bar {
    height: 50px;
    border-top: 1px solid #dcdfe6;
    text-align: right;
    line-height: 50px;
    padding-right: 10px;
  }
  .chart-box {
    border: 1px solid #dcdfe6;
    border-radius: 5px;
    &-info {
      height: 700px;
      border-bottom: 1px solid #dcdfe6;
    }
    &-input {
      height: 100px;
      text-align: right;
      padding: 0 10px;
      display: flex;
      flex-direction: column;
      justify-content: space-around;
    }
  }
}
</style>
